package com.gitee.wsl.common.chart.sample.funnel

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.sample.XChart
import com.gitee.wsl.common.chart.sample.funnel.model.FunnelData
import com.gitee.wsl.common.ui.draw.type.HorizontalAlign
import com.gitee.wsl.common.ui.draw.type.SortType
import com.gitee.wsl.android.ui.ext.type.textHeight
import com.gitee.wsl.android.ui.ext.type.textWidth


class FunnelChart :XChart() {
    val dataSet = mutableListOf<FunnelData>()
    var sortType = SortType.DESC

    //图的初始宽度
    var plotWidthPercent = 100f
    val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val funnelLinePaint: Paint by lazy {
       Paint(Paint.ANTI_ALIAS_FLAG).apply {
           strokeWidth = 5f
       }
    }
    var isFunnelLineVisible = true

    val labelPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val labelLinePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    //同步标签颜色
    var isLabelLineSyncColor = false
    var isLabelSyncColor = false
    var isShowLabelLine = false
    
    var labelAlign = HorizontalAlign.CENTER
        set(value) {
            field=value
            when (value) {
                HorizontalAlign.LEFT -> {
                    labelPaint.textAlign = Paint.Align.LEFT
                    isShowLabelLine = true
                }
                HorizontalAlign.CENTER -> labelPaint.textAlign = Paint.Align.CENTER
                HorizontalAlign.RIGHT -> {
                    labelPaint.textAlign = Paint.Align.RIGHT
                    isShowLabelLine = true
                }
                else -> labelPaint.textAlign = Paint.Align.CENTER
            }
        }
    
    var isLabelVisible = true


    override fun getType(): ChartEnum.ChartType {
        return ChartEnum.ChartType.FUNNEL
    }

    private fun sortDataSet(): Boolean {
        for (i in dataSet.indices.reversed()) {
            val d: FunnelData = dataSet[i]
            if (d.data.compareTo(0.0f) == -1 || d.data.compareTo(0.0f) == 0) {
                dataSet.removeAt(i)
            }
        }
        if (dataSet.size == 0) return false
        if (SortType.NORMAL != sortType)
            dataSet.sort()
        return true
    }

    private fun drawTriangle(
        canvas: Canvas,
        cx: Float, start: PointF, stop: PointF
    ) {
        val path = Path()
        path.moveTo(start.x, start.y)
        path.lineTo(stop.x, stop.y)
        when (sortType) {
            SortType.DESC -> path.lineTo(cx, bodyViewport.bottom)
            SortType.ASC, SortType.NORMAL -> path.lineTo(cx, bodyViewport.top)
            else -> path.lineTo(cx, bodyViewport.top)
        }
        path.close()
        paint.color = dataSet[0].color
        canvas.drawPath(path, paint)
    }

    private fun getHalfWidth(funnelWidth: Float, data: Float): Float {
        return funnelWidth * (data / 100) / 2
    }

    protected fun drawPlotDesc(
        canvas: Canvas,
        cx: Float,
        funnelWidth: Float,
        funnelHeight: Float
    ) {
        val count = dataSet.size
        var halfWidth = 0f
        var bottomY: Float = bodyViewport.bottom
        val pStart = PointF()
        val pStop = PointF()
        pStart.x = cx - bodyViewport.width / 2
        pStop.x = cx + bodyViewport.width / 2
        pStop.y = bodyViewport.bottom
        pStart.y = pStop.y
        halfWidth = funnelWidth / 2
        var labelY = 0f
        val path = Path()
        for (i in 0 until count) {
            val d: FunnelData = dataSet[i]
            path.reset()
            if (i == 0) {
                path.moveTo(cx, bodyViewport.bottom)
            } else {
                path.moveTo(pStart.x, pStart.y)
                path.lineTo(pStop.x, pStop.y)
            }
            halfWidth = getHalfWidth(funnelWidth, d.data)
            bottomY = bodyViewport.bottom- i * funnelHeight
            labelY = bottomY - funnelHeight / 2
            pStart.x = cx - halfWidth
            pStart.y = bottomY - funnelHeight
            pStop.x = cx + halfWidth
            pStop.y = bottomY - funnelHeight
            path.lineTo(pStop.x, pStop.y)
            path.lineTo(pStart.x, pStart.y)
            this.paint.setColor(d.color)
            path.close()
            if (d.alpha != -1) paint.setAlpha(d.alpha)
            canvas.drawPath(path, this.paint)
            if (d.alpha != -1) paint.alpha = 255
            if (i != count - 1 && isFunnelLineVisible) {
                canvas.drawLine(pStart.x, pStart.y, pStop.x, pStop.y, this.funnelLinePaint)
            }
            drawLabels(canvas, d.label, cx, labelY, d.color)
        }
    }

    protected fun drawPlotAsc(
        canvas: Canvas,
        cx: Float,
        funnelWidth: Float,
        funnelHeight: Float
    ) {
        val count = dataSet.size
        var halfWidth = 0f
        var bottomY: Float = bodyViewport.bottom
        val pStart = PointF()
        val pStop = PointF()
        pStart.x = cx - bodyViewport.width / 2
        pStop.x = cx + bodyViewport.width / 2
        pStop.y = bodyViewport.bottom
        pStart.y = pStop.y
        var labelY = 0f
        halfWidth = funnelWidth / 2
        val path = Path()
        for (i in 0 until count) {
            val d: FunnelData = dataSet[i]
            path.reset()
            if (i == 0) //三角
            {
                path.moveTo(cx, bodyViewport.top)
            } else {
                path.moveTo(pStart.x, pStart.y)
                path.lineTo(pStop.x, pStop.y)
            }
            halfWidth = getHalfWidth(funnelWidth, d.data)
            bottomY = bodyViewport.top+ i * funnelHeight
            labelY = bottomY + funnelHeight / 2
            pStart.x = cx - halfWidth
            pStart.y = bottomY + funnelHeight
            pStop.x = cx + halfWidth
            pStop.y = bottomY + funnelHeight
            path.lineTo(pStop.x, pStop.y)
            path.lineTo(pStart.x, pStart.y)
            path.close()
            this.paint.setColor(d.color)
            if (d.alpha != -1) paint.alpha = d.alpha
            canvas.drawPath(path, this.paint)
            if (d.alpha != -1) paint.alpha = 255
            if (i != count - 1 && isFunnelLineVisible) {
                canvas.drawLine(pStart.x, pStart.y, pStop.x, pStop.y, this.funnelLinePaint)
            }
            drawLabels(canvas, d.label, cx, labelY, d.color)
        }
    }

    private fun drawPlotOne(canvas: Canvas, cx: Float, funnelWidth: Float, funnelHeight: Float) {
        val d: FunnelData = dataSet[0]
        val halfWidth = getHalfWidth(funnelWidth, d.data)
        val pStart = PointF()
        val pStop = PointF()
        pStart.x = cx - halfWidth
        pStop.x = cx + halfWidth
        if (SortType.DESC == sortType) {
            pStop.y = bodyViewport.top
            pStart.y = pStop.y
        } else {
            pStop.y = bodyViewport.bottom
            pStart.y = pStop.y
        }
        if (d.alpha != -1) paint.alpha = d.alpha
        drawTriangle(canvas, cx, pStart, pStop)
        if (d.alpha != -1) paint.alpha = 255
        val labelY: Float = bodyViewport.bottom - bodyViewport.height / 2
        drawLabels(canvas, d.label, cx, labelY, d.color)
        return
    }

    protected fun drawLabels(canvas: Canvas, label: String, cx: Float, y: Float, color: Int) {
        if (!isLabelVisible) return
        if ("" === label) return
        if (isLabelLineSyncColor) {
            labelLinePaint.color = color
            labelPaint.color = color
        } else if (isLabelSyncColor) {
            labelPaint.color = color
        }
        if (isShowLabelLine) {
            val labelWidth = labelPaint.textWidth(label)
            when (labelAlign) {
                HorizontalAlign.LEFT -> canvas.drawLine(
                    cx,
                    y,
                    bodyViewport.left + labelWidth,
                    y,
                    labelLinePaint
                )
                HorizontalAlign.CENTER -> {}
                HorizontalAlign.RIGHT -> canvas.drawLine(
                    cx,
                    y,
                    bodyViewport.right - labelWidth,
                    y,
                    labelLinePaint
                )
                else -> {}
            }
        }
        var labelX = 0f
        var labelY = 0f
        labelX = when (labelAlign) {
            HorizontalAlign.LEFT -> bodyViewport.left
            HorizontalAlign.CENTER -> cx
            HorizontalAlign.RIGHT -> bodyViewport.right
            else -> cx
        }
        labelY = y + labelPaint.textHeight / 3
        canvas.drawText(label, labelX, labelY, labelPaint)
    }

    protected fun drawPlot(canvas: Canvas) {
        if (!sortDataSet()) return
        val count = dataSet.size
        val funnelWidth: Float = bodyViewport.width * (plotWidthPercent / 100)
        val funnelHeight: Float = bodyViewport.height / count
        val cx: Float = bodyViewport.centerX
        if (1 == count) {
            drawPlotOne(canvas, cx, funnelWidth, funnelHeight)
        }
        if (SortType.DESC == sortType) {
            drawPlotDesc(canvas, cx, funnelWidth, funnelHeight)
        } else {
            drawPlotAsc(canvas, cx, funnelWidth, funnelHeight)
        }
    }

    override fun readerBackground(canvas: Canvas) {
        super.readerBackground(canvas)

        //画Plot Area背景
        bodyViewport.render(canvas)
    }


    override fun renderBody(canvas: Canvas): Boolean {

            super.renderBody(canvas)

            /*//计算主图表区范围
            calcPlotRange()
            //画Plot Area背景			
            bodyViewport.render(canvas)
            //绘制标题
            drawTitle(canvas)*/

            //绘制图表
            drawPlot(canvas)

           /* //显示焦点
            drawFocusShape(canvas)

            //响应提示
            drawToolTip(canvas)*/

        return true
    }
    
}